CloudFormation で Aurora + RDS Proxy を作成してみた
はじめに
題名通り、CloudFormation で Aurora (MySQL) と RDS Proxy を作成します。
ただし、Aurora と RDS Proxy を作成する上で、以下のawsリソースも必要になりますので、CloudFormation のテンプレートに記載します。
- Secrets Manager (AuroraのDB情報を保存)
- IAM ロールとポリシー (RDS Proxy 用)
- セキュリティグループ (Aurora,RDS Proxy )
- インターフェイス型VPCエンドポイント (RDS Proxy が Secrets Manager にアクセスするため)
注意点として、RDS Proxy を作成すると、VPCエンドポイントは、自動作成されるようです。私は、ここでつまづきました。。
そのため、CloudFormation のテンプレートファイルには、VPCエンドポイントは、記載しません。
VPCエンドポイントの自動作成の挙動
ドキュメントでは該当の記述が見つけられませんでしたが、今回の CloudFormation での作成や、コンソール画面から RDS Proxy を作成し確認した限りでは、VPCエンドポイントは自動生成されておりました。
前提条件
- VPC と 2つの Private Subnet (アベイラビリティゾーン2つ) を作成済み
- RDS Proxy にアクセスする EC2 や Lambda の作成方法は説明しません。
構成図
前提条件にも記載しましたが、Lambda や EC2は、今回の CloudFormation では、作成しません。
テンプレートの作成
テンプレートは、ymlファイルを採用し、下記のymlファイルをそのままコピペして使用します。
RDS Proxy のセキュリティグループのインバウンドには、例として Lambda のセキュリティグループを作成し、許可するようにしています。
そのため、下記テンプレート内の Resources の LambdaSecurityGroup
は、個々で作成したいセキュリティグループに変えても大丈夫です。
CloudFormationテンプレート (クリックすると展開します)
AWSTemplateFormatVersion: '2010-09-09' Description: Create Aurora and RDS Proxy Parameters: PJPrefix: Type: String VpcId: Type: AWS::EC2::VPC::Id Description: vpc id EngineType: Type: String Default: aurora-mysql MySQLMajorVersion: Type: String Default: 5.7 MySQLMinorVersion: Type: String Default: 2.11.0 DBInstanceClass: Type: String Default: db.t3.small PrivateSubnetIdA: Type: AWS::EC2::Subnet::Id PrivateSubnetIdC: Type: AWS::EC2::Subnet::Id DatabaseName: Type: String MasterUsername: NoEcho: true Type: String MinLength: 1 MaxLength: 16 AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' ConstraintDescription: Must begin with a letter and contain only alphanumeric characters. MasterUserPassword: NoEcho: true Type: String MinLength: 8 MaxLength: 41 AllowedPattern: '[a-zA-Z0-9]*' ConstraintDescription: Must contain only alphanumeric characters. SecretsManagerKMSKeyId: Type: String Description: AWS managed key in aws/secretsmanager Resources: RDSProxySecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${PJPrefix}-rds-proxy GroupName: !Sub ${PJPrefix}-rds-proxy Tags: - Key: Name Value: !Sub ${PJPrefix}-rds-proxy SecurityGroupIngress: - SourceSecurityGroupId: !Ref LambdaSecurityGroup SourceSecurityGroupOwnerId: !Ref AWS::AccountId Description: !Sub ${PJPrefix}-lambda FromPort: 3306 IpProtocol: tcp ToPort: 3306 SecurityGroupEgress: - CidrIp: 0.0.0.0/0 IpProtocol: -1 VpcId: !Ref VpcId RDSSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${PJPrefix}-rds GroupName: !Sub ${PJPrefix}-rds SecurityGroupIngress: - SourceSecurityGroupId: !Ref RDSProxySecurityGroup SourceSecurityGroupOwnerId: !Ref AWS::AccountId Description: !Sub ${PJPrefix}-rds-proxy FromPort: 3306 IpProtocol: tcp ToPort: 3306 SecurityGroupEgress: - CidrIp: 0.0.0.0/0 IpProtocol: '-1' Tags: - Key: Name Value: !Sub ${PJPrefix}-rds VpcId: !Ref VpcId LambdaSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${PJPrefix}-lambda GroupName: !Sub ${PJPrefix}-lambda Tags: - Key: Name Value: !Sub ${PJPrefix}-lambda VpcId: !Ref VpcId SecurityGroupEgress: - CidrIp: 0.0.0.0/0 IpProtocol: '-1' DBCluster: Type: AWS::RDS::DBCluster DeletionPolicy: Delete Properties: BackupRetentionPeriod: 7 DatabaseName: !Ref DatabaseName DBSubnetGroupName: !Ref DBSubnetGroup DBClusterParameterGroupName: !Ref DBClusterParameterGroup DBClusterIdentifier: !Ref PJPrefix DeletionProtection: false Engine: !Ref EngineType EngineMode: provisioned EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion} MasterUsername: !Ref MasterUsername MasterUserPassword: !Ref MasterUserPassword PreferredBackupWindow: 16:00-17:00 PreferredMaintenanceWindow: tue:18:00-tue:19:00 StorageEncrypted: true VpcSecurityGroupIds: - !Ref RDSSecurityGroup DBClusterParameterGroup: Type: AWS::RDS::DBClusterParameterGroup Properties: Description: !Sub ${PJPrefix}-DBClusterParameterGroup Family: aurora-mysql5.7 Parameters: time_zone: Asia/Tokyo DBInstance: Type: AWS::RDS::DBInstance DeletionPolicy: Delete Properties: AutoMinorVersionUpgrade: false AvailabilityZone: !Sub ${AWS::Region}a DBClusterIdentifier: !Ref DBCluster DBParameterGroupName: !Ref DBParameterGroup DBInstanceClass: !Ref DBInstanceClass DBSubnetGroupName: !Ref DBSubnetGroup DBInstanceIdentifier: !Sub ${PJPrefix}-instance Engine: !Ref EngineType EngineVersion: !Sub ${MySQLMajorVersion}.mysql_aurora.${MySQLMinorVersion} EnablePerformanceInsights: false MonitoringInterval: 0 PubliclyAccessible: false PreferredMaintenanceWindow: tue:18:00-tue:19:00 PromotionTier: 1 DBParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Description: !Sub ${PJPrefix}-DBParameterGroup Family: !Sub ${EngineType}${MySQLMajorVersion} DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupName: !Sub ${PJPrefix}-subnet DBSubnetGroupDescription: '-' SubnetIds: - !Ref PrivateSubnetIdA - !Ref PrivateSubnetIdC DBProxy: Type: AWS::RDS::DBProxy Properties: Auth: - AuthScheme: SECRETS SecretArn: !Ref SecretsManager IAMAuth: DISABLED DBProxyName: !Ref PJPrefix DebugLogging: false EngineFamily: MYSQL IdleClientTimeout: 1800 RequireTLS: false RoleArn: !GetAtt RDSProxyIAMRole.Arn VpcSecurityGroupIds: - !Ref RDSProxySecurityGroup VpcSubnetIds: - !Ref PrivateSubnetIdA - !Ref PrivateSubnetIdC DBProxyTargetGroup: Type: AWS::RDS::DBProxyTargetGroup Properties: ConnectionPoolConfigurationInfo: MaxConnectionsPercent: 100 MaxIdleConnectionsPercent: 50 ConnectionBorrowTimeout: 120 DBProxyName: !Ref DBProxy DBClusterIdentifiers: - !Ref DBCluster TargetGroupName: default SecretsManager: Type: AWS::SecretsManager::Secret Properties: Name: !Sub ${PJPrefix}-proxy Description: !Sub ${PJPrefix}-proxy SecretString: !Sub '{ "username": "${MasterUsername}", "password": "${MasterUserPassword}", "engine":"mysql", "host": "${DBCluster.Endpoint.Address}", "port":"3306", "dbClusterIdentifier": "${DBCluster}" }' Tags: - Key: Name Value: !Sub ${PJPrefix}-rds-proxy RDSProxyIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - rds.amazonaws.com Action: - sts:AssumeRole MaxSessionDuration: 3600 ManagedPolicyArns: - !Ref SecretsManagerManagedPolicy Path: /service-role/ RoleName: !Sub ${PJPrefix}-rds-proxy SecretsManagerManagedPolicy: Type: AWS::IAM::ManagedPolicy Properties: Description: Get values from Secrets Manager ManagedPolicyName: !Sub ${PJPrefix}-rds-proxy Path: / PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue Resource: !Ref SecretsManager - Effect: Allow Action: - kms:Decrypt Resource: !Sub arn:aws:kms:${AWS::Region}:${AWS::AccountId}:key/${SecretsManagerKMSKeyId} Condition: StringEquals: kms:ViaService: !Sub secretsmanager.${AWS::Region}.amazonaws.com
パラメータ SecretsManagerKMSKeyId の説明
Secrets Manager では、KMS キーで暗号化を行うため、KMS キーが必要になります。
KMS キーには、AWS マネージド型キー
と カスタマー管理型のキー
の2種類ありますが、今回は、AWS マネージド型キー
を利用します。
スタックのパラメータのうち SecretsManagerKMSKeyId
は、 AWS マネージド型キー
のエイリアスaws/secretsmanager
のキーIDの値になります。
KMS キー aws/secretsmanager
が存在しない場合、Secrets Manager を利用されたことがない可能性があります。
適当にシークレットを作成すると、表示されるようになります。
Secrets Managerのコンソールに移動し、適当にシークレットを作成すると、キーが作成されます。
このキーIDをSecretsManagerKMSKeyId
に指定しましょう。
スタック作成
スタックを作成しましょう。
スタックが作成されるまで20分弱かかります。
成功を確認後、以下のリソースが作成されているか確認しましょう。
- Aurora (MySQL)
- RDS Proxy
- Secrets Manager (AuroraのDB情報を保存)
- IAM ロールとポリシー(RDS Proxy用)
- セキュリティグループ (Aurora, RDS Proxy, Lambda用)
- VPCエンドポイント
無事、作成することができました。
コンソールではなく、CloudFormation を利用することで、必要なときにパッと作成することができるので、便利ですね!
参考
AWS CloudFormation の Template reference